//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Query Application Block
//===============================================================================

using System;
using System.Data;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using Microsoft.Practices.EnterpriseLibrary.Configuration.Design;
using Microsoft.Practices.EnterpriseLibrary.Configuration.Design.Validation;
using Microsoft.Practices.EnterpriseLibrary.Data.Configuration.Design;
using EntLibContrib.Query.Properties;

namespace EntLibContrib.Query.Configuration.Design
{
  /// <summary>
  /// Represents a query using a database.
  /// </summary>
  public sealed class DataQueryNode : QueryNode
	{
		#region Fields
		private ConnectionStringSettingsNode connectionStringSettingsNode;
		private EventHandler<ConfigurationNodeChangedEventArgs> onConnectionNodeRemoved;
		private EventHandler<ConfigurationNodeChangedEventArgs> onConnectionNodeRenamed;
		internal string connectionStringName;
		private string command;
		private CommandType commandType;
		#endregion

		#region Properties
		/// <summary>
		/// Gets the name of the custom data command to use for this query.
		/// </summary>
		/// <value>The name of the custom data command to use for this query.</value>
		[Editor(typeof(ReferenceEditor), typeof(UITypeEditor))]
		[ReferenceType(typeof(DataCommandNode))]
		[QueryCategory("CategoryCustom")]
		[QueryDescription("DataQueryCommandNameDescription")]
		public DataCommandNode DataCommandName
		{
			get { return (DataCommandNode)CustomCommand; }
			set
			{
				CustomCommand = LinkNodeHelper.CreateReference<DataCommandNode>(DataCommandName,
																																						value,
																																						OnCustomCommandNodeRemoved,
																																						OnCustomCommandNodeRenamed);
				CustomCommandName = (null == CustomCommand) ? string.Empty : CustomCommand.Name;
			}
		}

		/// <summary>
		/// Gets or sets the database to use for the query.
		/// </summary>
		/// <value>
		/// The database to use for the query.
		/// </value>
		[Required]
		[Editor(typeof(ReferenceEditor), typeof(UITypeEditor))]
		[ReferenceType(typeof(ConnectionStringSettingsNode))]
		[QueryCategory("CategoryProvider")]
		[QueryDescription("DatabaseInstanceDescription")]
		public ConnectionStringSettingsNode DatabaseInstance
		{
			get { return connectionStringSettingsNode; }
			set
			{
				connectionStringSettingsNode = LinkNodeHelper.CreateReference<ConnectionStringSettingsNode>(connectionStringSettingsNode,
																																																		value,
																																																		onConnectionNodeRemoved,
																																																		onConnectionNodeRenamed);
				connectionStringName = (null == connectionStringSettingsNode) ? string.Empty : connectionStringSettingsNode.Name;
			}
		}

		/// <summary>
		/// Gets or sets the query command string.
		/// </summary>
		/// <value>The query command string for this node.</value>
		[Required]
		[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
		[QueryCategory("CategoryProvider")]
		[QueryDescription("DataQueryCommandDescription")]
		public string Command
		{
			get { return command; }
			set
			{
				if (value != null)
					command = value;
			}
		}

		/// <summary>
		/// Gets or sets the query command type.
		/// </summary>
		/// <value>The query command type for this node.</value>
		[Required]
		[QueryCategory("CategoryProvider")]
		[QueryDescription("DataQueryCommandTypeDescription")]
		public CommandType CommandType
		{
			get { return commandType; }
			set { commandType = value; }
		}

		/// <summary>
		/// Gets or sets the name of the connection string.
		/// </summary>
		/// <value>The name of the connection string.</value>
		[Browsable(false)]
		public string ConnectionStringName
		{
			get { return connectionStringName; }
			set { connectionStringName = value; }
		}

		/// <summary>
		/// Gets a <see cref="DataQueryData"/> configuration object using the node data.
		/// </summary>
		/// <value>
		/// A <see cref="DataQueryData"/> configuration object using the node data.
		/// </value>
		[ReadOnly(true)]
		public override QueryDataBase QueryData
		{
			get { return new DataQueryData(Name, CustomCommandName, ParameterSetName, connectionStringName, command, commandType); }
		}
		#endregion

		#region Construction
		/// <summary>
		/// Initialize a new instance of the <see cref="DataQueryNode"/> class.
		/// </summary>
		public DataQueryNode ()
			: this(new DataQueryData(InternalResources.DefaultDataQueryNodeName, string.Empty, string.Empty, string.Empty, string.Empty, CommandType.StoredProcedure))
    {
    }

		/// <summary>
		/// Initialize a new instance of the <see cref="DataQueryNode"/> class with a <see cref="DataQueryData"/> configuration object.
		/// </summary>
		/// <param name="dataQueryData">A <see cref="DataQueryData"/> configuration object</param>
    public DataQueryNode(DataQueryData dataQueryData) 
    {
			if (dataQueryData == null)
				throw new ArgumentNullException("dataQueryData");

			Rename(dataQueryData.Name);
			this.onConnectionNodeRemoved = new EventHandler<ConfigurationNodeChangedEventArgs>(OnConnectionStringSettingsNodeRemoved);
			this.onConnectionNodeRenamed = new EventHandler<ConfigurationNodeChangedEventArgs>(OnConnectionStringSettingsRenamed);
			base.CustomCommandName = dataQueryData.CustomCommandName;
			base.ParameterSetName = dataQueryData.ParameterSetName;
			this.connectionStringName = dataQueryData.DatabaseInstanceName;
			this.command = dataQueryData.Command;
			this.commandType = dataQueryData.CommandType;
		}
		#endregion

		#region Protected Methods
		/// <summary>
		/// Releases the unmanaged resources used by the <see cref="DataQueryNode "/> and optionally releases the managed resources.
		/// </summary>
		/// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
		protected override void Dispose (bool disposing)
		{
			try
			{
				if ( disposing )
				{
					if ( connectionStringSettingsNode != null )
					{
						connectionStringSettingsNode.Removed -= onConnectionNodeRemoved;
						connectionStringSettingsNode.Renamed -= onConnectionNodeRenamed;
					}
				}
			}
			finally
			{
				base.Dispose(disposing);
			}
		}
		#endregion

		#region Private Methods
		private void OnConnectionStringSettingsNodeRemoved (object sender, ConfigurationNodeChangedEventArgs e)
    {
      connectionStringSettingsNode = null;
    }

		private void OnConnectionStringSettingsRenamed(object sender, ConfigurationNodeChangedEventArgs e)
		{
			connectionStringName = e.Node.Name;
		}
		#endregion
	}
}